package seqAlignment;

import java.awt.Point;

import seqAlignment.utils.MatrixOut;

public class AffineGPLocalAligner extends LocalAligner {
	int[][] matrixX;
	int[][] matrixY;
	AffineGPPoint[][] pathX;
	AffineGPPoint[][] pathY;
	
	public void init() {
		super.init();
		matrixX=new int[str1.length()+1][str2.length()+1];
		matrixY=new int[str1.length()+1][str2.length()+1];
		
		pathX = new AffineGPPoint[str1.length()+1][str2.length()+1];
		pathY = new AffineGPPoint[str1.length()+1][str2.length()+1];
		
		initMatrixs();
	}
	
	private void initMatrixs() {
		for (int i=0;i<matrix.length;i++) {
			matrix[i][0]=0;
			matrixX[i][0]=Integer.MIN_VALUE;
			matrixY[i][0]=Integer.MIN_VALUE;
		}
		for (int i=1;i<matrix[0].length;i++) {
			matrix[0][i]=0;
			matrixX[0][i]=Integer.MIN_VALUE;
			matrixY[0][i]=Integer.MIN_VALUE;
		}
	}
	
	@Override
	protected void getLocalPath(int x, int y) {
		//populate M
		int xM = add(matrixX[x-1][y-1],scoreFunction.score(matrix, x, y));
		int yM= add(matrixY[x-1][y-1],scoreFunction.score(matrix, x, y));
		int mM = add(matrix[x-1][y-1],scoreFunction.score(matrix, x, y));
		int max = Math.max( Math.max(xM,yM), mM);
		max = Math.max(max, 0);
		matrix[x][y]=max;

	//higher
		if (max==xM) {
			path[x][y]= new AffineGPPoint(pathX,x-1,y-1);
		} 
		else if (max==mM) {
			path[x][y] = new AffineGPPoint(path,x-1,y-1);
		}
		else if (max==yM){
			path[x][y] = new AffineGPPoint(pathY,x-1,y-1);
		}		
		else {
			path[x][y]=null;
		}
		
		if (max>=matrixMax) {
			matrixMax=max;
			matrixMaxPoint=new AffineGPPoint(path,x,y);
		}
		
		//populate X
		int mX=add(matrix[x-1][y],penaltyFunction.headPenalty(x-1,y)+penaltyFunction.gapPenalty(x-1,y));
		int xX=add(matrixX[x-1][y],penaltyFunction.gapPenalty(x-1,y));
		if (xX>mX) {
			matrixX[x][y]=xX;
			pathX[x][y]=new AffineGPPoint(pathX,x-1,y);
		}
		else {
			matrixX[x][y]=mX;
			pathX[x][y]=new AffineGPPoint(path,x-1,y);
		}
		
		//populate y
		int mY=add(matrix[x][y-1],penaltyFunction.headPenalty(x,y-1)+penaltyFunction.gapPenalty(x,y-1));
		int yY=add(matrixY[x][y-1],penaltyFunction.gapPenalty(x,y-1));
		if (mY>yY) {
			matrixY[x][y]=mY;
			pathY[x][y]=new AffineGPPoint(path,x,y-1);
		}
		else {
			matrixY[x][y]=yY;
			pathY[x][y]=new AffineGPPoint(pathY,x,y-1);
		}
	}
	
	protected int add(int i, int j) {
		if (i==Integer.MIN_VALUE) {
			return i;
		}
		if (j==Integer.MIN_VALUE) {
			return j;
		}
		return i+j;
	}

	@Override
	protected Point getNextPath(Point current) {
		super.getNextPath(current);
		AffineGPPoint curr=(AffineGPPoint)current;
		return curr.getPath()[curr.x][curr.y];
	}

/*
	@Override
	public void align() {
		super.align();
		System.out.println("M");
		MatrixOut.out(matrix);
		System.out.println("X");
		MatrixOut.out(matrixX);
		System.out.println("Y");
		MatrixOut.out(matrixY);
		MatrixOut.out(path,pathX, pathY);
	}
*/	
	
}
